/**
 * 
 */
package net.svenbuschbeck.gwt.ao.client.events;

import com.google.gwt.event.shared.GwtEvent;

/**
 * 
 * 
 * @author Sven Buschbeck
 * @param <T>
 * 
 */
public class ValueChangedEvent<T> extends GwtEvent<ValueChangedHandler<T>> {

	private static Type<ValueChangedHandler<?>> TYPE;

	private T oldValue;
	private T newValue;

	/**
	 * @param value
	 */
	protected ValueChangedEvent(T oldValue, T newValue) {
		this.setOldValue(oldValue);
		this.setNewValue(newValue);
	}

	/**
	 * Determines if oldValue is different from newValue
	 * 
	 * @param <T>
	 * @param source
	 * @param oldValue
	 * @param newValue
	 * @return true if oldValue != newValue
	 */
	public static <T> boolean shouldFire(HasValueChangedHandlers<T> source, T oldValue, T newValue) {
		return TYPE != null && oldValue != newValue && (oldValue == null || !oldValue.equals(newValue));
	}

	/**
	 * Fires a ValueChangedEvent if oldValue != newValue
	 * 
	 * @param <T>
	 * @param source
	 * @param oldValue
	 * @param newValue
	 */
	public static <T> boolean fireIfNotEqual(HasValueChangedHandlers<T> source, T oldValue, T newValue) {
		return fireIfNotEqual(source, oldValue, newValue, false);
	}

	/**
	 * Fires a ValueChangedEvent if oldValue != newValue
	 * 
	 * @param <T>
	 * @param source
	 * @param oldValue
	 * @param newValue
	 */
	public static <T> boolean fireIfNotEqual(HasValueChangedHandlers<T> source, T oldValue, T newValue,
		boolean forceUpdate) {
		boolean fire = forceUpdate || shouldFire(source, oldValue, newValue);
		if (fire) {
			ValueChangedEvent<T> event = new ValueChangedEvent<T>(oldValue, newValue);
			source.fireEvent(event);
		}
		return fire;
	}

	/**
	 * Fires a value change event on all registered handlers in the handler
	 * manager. If no such handlers exist, this method will do nothing.
	 * 
	 * @param <T>
	 *            the old value type
	 * @param source
	 *            the source of the handlers
	 * @param oldValue
	 *            value before the change
	 * @param newValue
	 *            value after the change
	 */
	public static <T> void fire(HasValueChangedHandlers<T> source, T oldValue, T newValue) {
		if (TYPE != null) {
			ValueChangedEvent<T> event = new ValueChangedEvent<T>(oldValue, newValue);
			source.fireEvent(event);
		}
	}

	/**
	 * Gets the type associated with this event.
	 * 
	 * @return returns the handler type
	 */
	public static Type<ValueChangedHandler<?>> getType() {
		if (TYPE == null) {
			TYPE = new Type<ValueChangedHandler<?>>();
		}
		return TYPE;
	}

	/**
	 * The value after the change.
	 * 
	 * @param newValue
	 */
	public void setNewValue(T newValue) {
		this.newValue = newValue;
	}

	/**
	 * The value after the change.
	 * 
	 * @return value after change.
	 */
	public T getNewValue() {
		return newValue;
	}

	/**
	 * The value before the change.
	 * 
	 * @param oldValue
	 */
	public void setOldValue(T oldValue) {
		this.oldValue = oldValue;
	}

	/**
	 * The value before the change.
	 * 
	 * @return value before change
	 */
	public T getOldValue() {
		return oldValue;
	}

	/**
	 * @see #setNewValue(Object)
	 * @param value
	 *            after change
	 */
	public void setValue(T value) {
		setNewValue(value);
	}

	/**
	 * @see #getNewValue()
	 * 
	 * @return getNewValue()
	 */
	public T getValue() {
		return getNewValue();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event.shared
	 * .EventHandler)
	 */
	@Override protected void dispatch(ValueChangedHandler<T> handler) {
		handler.onValueChanged(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.gwt.event.shared.GwtEvent#getAssociatedType()
	 */
	@SuppressWarnings({ "unchecked" }) @Override public com.google.gwt.event.shared.GwtEvent.Type<ValueChangedHandler<T>> getAssociatedType() {
		return (Type) TYPE;
	}

}
